using System.Diagnostics;
using Fine.Collections.Intf;
using Fine.TestUtils;
using Fine.Utils.Structs;
using NUnit.Framework;
using System.Linq;



namespace Fine.Collections.Const
{
    [TestFixture]
    public class ConstSortMap_test
    {

        [Test]
        public void Test_Basic()
        {
            var entries = new[]
                          {
                              new ComparableMapEntry<long,long>(1001, 100001), 
                              new ComparableMapEntry<long,long>(2002, 200002), 
                              new ComparableMapEntry<long,long>(3003, 300003), 
                          };
            var map = new ConstSortMap<long,long>(-7, entries);

            map.FirstIndex     ._equals_(-7);
            map.LastIndex      ._equals_(-5);

            map.IsEmpty        ._false_();
            map.IsNotEmpty     ._true_();
            map.Count          ._equals_(3);

            map[1001]          ._equals_(100001);
            map[2002]          ._equals_(200002);
            map[3003]          ._equals_(300003);
        }


        [Test]
        public void Test_Keys()
        {
            var map = MakeMap("eins:1111", "zwei:2222", "drei:3333");
            var keys = map.Keys;

            keys.IsEmpty              ._false_();
            keys.IsNotEmpty           ._true_();
            keys.Count                ._equals_(3);
            keys.FirstIndex           ._equals_(1);
            keys.LastIndex            ._equals_(3);
                                      
            keys.Contains("eins")     ._true_();
            keys.Contains("zwei")     ._true_();
            keys.Contains("drei")     ._true_();

            Enumerable.ToArray(keys)  ._array_("drei", "eins", "zwei");
        }


        [Test]
        public void Test_Values()
        {
            var map = MakeMap("eins:1111", "zwei:2222", "drei:3333");
            var values = map.Values;

            values.IsEmpty          ._false_();
            values.IsNotEmpty       ._true_();
            values.Count            ._equals_(3);
            values.FirstIndex       ._equals_(1);
            values.LastIndex        ._equals_(3);

            values.OrderBy(x => x).ToArray()  ._array_("1111","2222","3333");

            Enumerable.Contains(values, "1111") ._true_();
            Enumerable.Contains(values, "2222") ._true_();
            Enumerable.Contains(values, "3333") ._true_();
        }


        [Test]
        public void Test_Entries()
        {
            var map = MakeMap("eins:1111", "zwei:2222", "drei:3333");
            var entries = map.Entries;

            entries.IsEmpty          ._false_();
            entries.IsNotEmpty       ._true_();
            entries.Count            ._equals_(3);
            entries.FirstIndex       ._equals_(1);
            entries.LastIndex        ._equals_(3);

            entries.Find(e => e.Key == "eins").Found  ._true_();
            entries.Find(e => e.Key == "zwei").Found  ._true_();
            entries.Find(e => e.Key == "drei").Found  ._true_();
        }


        [Test]
        public void Test_Sort()
        {
            var entries = new[]
                          {
                              new ComparableMapEntry<long,long>(3003, 300003), 
                              new ComparableMapEntry<long,long>(1001, 100001), 
                              new ComparableMapEntry<long,long>(5005, 500005), 
                              new ComparableMapEntry<long,long>(4004, 400004), 
                              new ComparableMapEntry<long,long>(2002, 200002), 
                          };
            var map = new ConstSortMap<long,long>(1, entries);
            
            map.Keys[1]  ._equals_(1001);
            map.Keys[2]  ._equals_(2002);
            map.Keys[3]  ._equals_(3003);
            map.Keys[4]  ._equals_(4004);
            map.Keys[5]  ._equals_(5005);
        }


        [TestCase(11,22,22,22,33)]
        [TestCase(11,11,11,22,33)]
        [TestCase(11,22,33,33,33)]
        [TestCase(11,22,33,11,22)]
        [TestCase(11,22,11,33,11)]
        [TestCase(22,11,22,33,22)]
        public void Test_Duplicates(int k1, int k2, int k3, int k4, int k5)
        {
            var entries = new[]
                          {
                              new ComparableMapEntry<int,int>(k1, k1), 
                              new ComparableMapEntry<int,int>(k2, k2), 
                              new ComparableMapEntry<int,int>(k3, k3), 
                              new ComparableMapEntry<int,int>(k4, k4), 
                              new ComparableMapEntry<int,int>(k5, k5), 
                          };
            var map = new ConstSortMap<int,int>(1, entries);
            
            map.Keys[1]  ._equals_(11);
            map.Keys[2]  ._equals_(22);
            map.Keys[3]  ._equals_(33);
        }


        [Test]
        public void Test_Empty()
        {
            var map = new ConstSortMap<long,long>(0, new ComparableMapEntry<long,long>[0]);

            map.Count              ._equals_(0);
            map.IsEmpty            ._true_();
            map.IsNotEmpty         ._false_();
            map.Keys.IsEmpty       ._true_();
            map.Keys.IsNotEmpty    ._false_();
            map.Values.IsEmpty     ._true_();
            map.Values.IsNotEmpty  ._false_();
            map.Entries.IsEmpty    ._true_();
            map.Entries.IsNotEmpty ._false_();

            map.ContainsKey(333L)  ._false_(); 
        }


        [Test]
        public void Test_IndexOf_basic()
        {
            var map = MakeMap("aaaa:1111", "bbbb:2222", "cccc:3333");

            int x1 = map.IndexOf("aaaa");
            int x2 = map.IndexOf("bbbb");
            int x3 = map.IndexOf("cccc");

            x1    ._equals_(map.FirstIndex);
            x2    ._equals_(map.FirstIndex+1);
            x3    ._equals_(map.LastIndex);
        }


        [Test]
        public void Test_IndexOf_emptymap()
        {
            var map = new int[0].ToSortMap(x => 0, x => 0);

            int xxx = map.IndexOf(666);

            xxx   ._equals_(int.MinValue);
        }


        [Test]
        public void Test_ContainsKey_basic()
        {
            var map = MakeMap("aaaa:1111", "bbbb:2222", "cccc:3333");

            map.ContainsKey("aaaa")   ._true_();
            map.ContainsKey("bbbb")   ._true_();
            map.ContainsKey("cccc")   ._true_();

            map.ContainsKey("dddd")   ._false_();
            map.ContainsKey(null)     ._false_();
        }


        [Test]
        public void Test_ContainsKey_empty()
        {
            var map = MakeMap();

            map.ContainsKey("aaaa")   ._false_();
            map.ContainsKey(null)     ._false_();
        }


        private static ConstSortMap<string, string> MakeMap(params string[] strings)
        {
            return strings
                .Select(str => str.ToPair())
                .ToSortMap(p => p.A, p => p.B, 7);
        }


    }


    static class LocalStringUtils
    {
        internal static Pair<string> ToPair(this string str)
        {
            int p = str.IndexOf(':');
            Debug.Assert(p >= 0);

            string strA = str.Substring(0, p);
            string strB = str.Substring(p + 1);

            return new Pair<string>(strA, strB);
        }
    }
}